-- 逻辑处理模块
-- 2021.05.15
-- Lingd
-- 福州泰诚网络科技有限公司

module(...,package.seeall)

require "metering"
require "hc595"
require "nvm"
require "bit"
require "serptl"
require "usart"
require "audio"

-- 变量声明
local MeuMaxU = 0                   -- 最大电压（V）
local MeuMinU = 0                   -- 最小电压（V）
local MeuMaxI = 0                   -- 最大电流（A）
local MeuMinI = 0                   -- 最小电流（A）
local MeuFI   = 0                   -- 浮充电流（A）
local MeuBNum = 0                   -- 异常保护次数 
local MeuBTime= 0                   -- 异常保护时间（ms）
local MeuKTime= 0                   -- 空载时间（ms） 
local MeuFTime= 0                   -- 浮充时间（ms）
RmbTime       = 0                   -- 1元的充电时间（ms）

PORT_NUM      = 8                   -- 设备端口数量

PORT_STATE_1  = "0"					-- 空闲状态
PORT_STATE_2  = "1"					-- 忙状态
PORT_STATE_3  = "2"					-- 故障状态
PORT_STATE_4  = "3"					-- 浮充状态

-- 倒计时变量
UbTimer     	= 0                     -- 过欠压保护倒计时
UbNum       	= 0                     -- 过欠压保护次数
IbTime      	= {0,0,0,0,0,0,0,0}     -- 过流保护倒计时
IbNum       	= {0,0,0,0,0,0,0,0}     -- 过流保护次数
FbTime      	= {0,0,0,0,0,0,0,0}     -- 浮充倒计时
KbTime      	= {0,0,0,0,0,0,0,0}     -- 空载倒计时
CdTime      	= {0,0,0,0,0,0,0,0}     -- 设备端口时间
PortState   	= {"0","0","0","0","0","0","0","0"}     -- 设备端口状态，初始化为空闲
BakKState      = 0x00                  					-- 用于过欠压保护时，备份输出通道的状态
BakLedState    = 0x0000                					-- 用于过欠压保护时，备份输出通道的指示灯状态
BakPortState   = {"0","0","0","0","0","0","0","0"}     	-- 用于过欠压保护时，备份设备端口状态，初始化为空闲

-- 停止充电，清除该路所有变量（ch 1~8）
function end_charge(ch)
    CdTime[ch] = 0                  -- 充电时间
    IbTime[ch] = 0                  -- 过流保护时间
    IbNum[ch]  = 0                  -- 过流保护次数
    FbTime[ch] = 0                  -- 浮充时间
    KbTime[ch] = 0                  -- 空载时间
	PortState[ch] = PORT_STATE_1	-- 空闲状态
    hc595.LED_ChargeOff(ch)         -- 关闭指示灯
    hc595.K_Off(ch)                 -- 关闭继电器
	BakKState   = hc595.Data[4]                                        -- 备份输出通道状态
    BakLedState = bit.bor(bit.lshift(hc595.Data[3],8),hc595.Data[2])   -- 备份输出通道的指示灯状态
end

-- 开始充电，清除该路所有变量（ch 1~8）
function start_charge(ch,time)
    CdTime[ch] = time               -- 充电时间
    IbTime[ch] = 0                  -- 过流保护时间
    IbNum[ch]  = 0                  -- 过流保护次数
    FbTime[ch] = 0                  -- 浮充时间
    KbTime[ch] = 0                  -- 空载时间
	PortState[ch] = PORT_STATE_2	-- 忙状态
    hc595.LED_ChargeRedOn(ch)       -- 开启红色指示灯
    hc595.K_On(ch)                  -- 开启继电器
	BakKState   = hc595.Data[4]                                        -- 备份输出通道状态
    BakLedState = bit.bor(bit.lshift(hc595.Data[3],8),hc595.Data[2])   -- 备份输出通道的指示灯状态
end

-- 1秒定时器
local function timer_1s()
	--log.info("mem:",_G.collectgarbage("count"))  	-- 打印占用的RAM
	--log.info("flash:",rtos.get_fs_free_size()) 	-- 打印剩余FALSH，单位Byte
    local i = 1
    -- 过欠压倒计时
    if UbTimer > 0 then
        UbTimer = UbTimer - 1
        if UbTimer == 0 then  
            if metering.Urms > MeuMinU and metering.Urms < MeuMaxU then
                hc595.LED_Show(hc595.DEV_SYS,hc595.LED_GREEN,1000,1000)     -- 系统红灯开始闪烁
                hc595.K_On_Rec(BakKState)              -- 恢复继电器输出
                hc595.LED_ChargeRec(BakLedState)       -- 恢复指示灯状态
				PortState = BakPortState				-- 恢复端口状态
            else
                UbTimer = MeuBTime                  	-- 赋值开始倒计时
            end
        end
    end

    -- 空载倒计时
    for i = 1,PORT_NUM do
        if KbTime[i] > 0 then
            KbTime[i] = KbTime[i] - 1
            -- 空载倒计时结束，则关闭输出，清除该通道的所有参数
            if KbTime[i] == 0 then
				serptl.SendEndChargeInfo(i,1)			-- 上报结束状态信息（空载结束）
                end_charge(i)                        	-- 关闭输出，并清除变量
            end
        end
    end

    -- 浮充倒计时
    for i = 1,PORT_NUM do
        if FbTime[i] > 0 then
            FbTime[i] = FbTime[i] - 1
            -- 浮充倒计时结束，则关闭输出，清除该通道的所有参数
            if FbTime[i] == 0 then
				serptl.SendEndChargeInfo(i,0)			-- 上报结束状态信息（充满结束）
				end_charge(i)                        	-- 关闭输出，并清除变量
            end
        end
    end

    -- 过流保护时间倒计时
    for i = 1,PORT_NUM do
        if IbTime[i] > 0 then
            IbTime[i] = IbTime[i] - 1
            -- 过流保护时间倒计时结束
            if IbTime[i] == 0 then
                hc595.LED_ChargeRedOn(i)        -- 开启充电红色指示灯
                hc595.K_On(i)                   -- 开启继电器
                hc595.LED_Show(hc595.DEV_SYS,hc595.LED_GREEN,1000,1000)             -- 系统红灯开始闪烁
            end
        end
    end

    -- 充电时间倒计时
    for i = 1,PORT_NUM do
        if CdTime[i] > 0 then
            CdTime[i] = CdTime[i] - 1
            -- 充电时间倒计时结束，则关闭输出，清除该通道的所有参数
            if CdTime[i] == 0 then
				serptl.SendEndChargeInfo(i,7)		-- 上报结束状态信息（时间用完结束）
                end_charge(i)                    	-- 关闭输出，并清除变量
            end
        end
    end
end

-- 定时监控
local function monitor()
    local i = 1

	-- 芯片受到干扰复位了，需要重新配置一下
	if metering.Urms == 0 then
		metering.pack(metering.ID_1,metering.REG_SYSCTRL,metering.RA,{0x00,0x00,0x80,0x38})
		sys.timerStart(usart.send_reglist,metering.SlotTime)
	end
	
    if metering.Urms > MeuMinU and metering.Urms < MeuMaxU and UbTimer == 0 then
        for i = 1,PORT_NUM do
            -- 充电时间是否大于0
            if CdTime[i] > 0 and IbTime[i] == 0 then
                -- 电流是否大于最小电流（浮充 或 正常）
                if metering.Irms[i] > MeuMinI then
                    -- 电流是否大于浮充电流（正常）
                    if metering.Irms[i] > MeuFI then
						if FbTime[i] > 0 then
							FbTime[i] = 0               -- 清除浮充倒计时 
							PortState[i] = PORT_STATE_2	-- 忙状态
							serptl.SendPortState()		-- 上报端口状态	
						end						
                    --（浮充）
                    elseif FbTime[i] == 0 then 
                        FbTime[i] = MeuFTime            -- 赋值开始倒计时
						PortState[i] = PORT_STATE_4		-- 浮充状态
						serptl.SendPortState()			-- 上报端口状态
                    end
                    KbTime[i] = 0                       -- 清除空载倒计时
                    hc595.LED_ChargeGreenOn(i)          -- 开启绿灯
                end

                -- 电流是否小于最小电流（空载）
                if metering.Irms[i] < MeuMinI then
                    if KbTime[i] == 0 then
                        KbTime[i] = MeuKTime                -- 赋值开始倒计时
                    end
                    hc595.LED_ChargeRedOn(i)                -- 开启红灯
                end

                -- 电流是否大于最大电流（过流）
                if metering.Irms[i] > MeuMaxI then
                    if IbTime[i] == 0 then
                        IbTime[i] = MeuBTime                -- 赋值开始倒计时
                    end
                    -- 是否已达到过载次数
                    IbNum[i] = IbNum[i] + 1
                    if IbNum[i] >= MeuBNum then
						serptl.SendEndChargeInfo(i,2)		-- 上报结束状态信息（过载结束）
						end_charge(i)                    	-- 关闭输出，并清除变量
                    else
                        hc595.K_Off(i)                      -- 立即关闭继电器输出
                        hc595.LED_ChargeRedOn(i)            -- 开启红灯
                        hc595.LED_Show(hc595.DEV_SYS,hc595.LED_RED,100,100)             -- 系统红灯开始闪烁
						audio.setStrategy(1)
						audio.play(1,"TTS",serptl.ChineseTab[i].." 路 充电器故障，请检查充电器",5,nil,false)
					end
                end
            end
        end
    -- 过欠压保护
    elseif UbNum < MeuBNum and UbTimer == 0 then     
        BakKState   = hc595.Data[4]                                        -- 备份输出通道状态
        BakLedState = bit.bor(bit.lshift(hc595.Data[3],8),hc595.Data[2])   -- 备份输出通道的指示灯状态
        BakPortState = PortState										-- 备份端口状态
		hc595.K_Off_All()                                               -- 断开所有输出
        hc595.LED_ChargeOff_All()                                       -- 关闭所有通道指示灯
        hc595.LED_Show(hc595.DEV_SYS,hc595.LED_RED,100,100)             -- 系统红灯开始闪烁
        UbTimer = MeuBTime                                              -- 赋值开始倒计时
    end
end

-- 获取系统配置
function getcfg()
	MeuMaxU = nvm.get("MeuMaxU")            -- 最大电压（V）
    MeuMinU = nvm.get("MeuMinU")            -- 最小电压（V）
    MeuMaxI = nvm.get("MeuMaxI")            -- 最大电流（A）
    MeuMinI = nvm.get("MeuMinI")            -- 最小电流（A）
    MeuFI   = nvm.get("MeuFI")              -- 浮充电流（A）
    MeuBNum = nvm.get("MeuBNum")            -- 异常保护次数 
    MeuBTime= nvm.get("MeuBTime")           -- 异常保护时间（ms）
    MeuKTime= nvm.get("MeuKTime")           -- 空载时间（ms） 
    MeuFTime= nvm.get("MeuFTime")           -- 浮充时间（ms）
    RmbTime = nvm.get("RmbTime")            -- 1元的充电时间（ms）
end


sys.taskInit(function()
    sys.wait(5000)                          -- 开机5秒后，再开始监测

    getcfg()

    -- 开启定时监控处理
    sys.timerLoopStart(monitor,1000)
    sys.timerLoopStart(timer_1s,1000)
end)

